#include "graph.h"

// ========================================================================
// CSV文件加载实现
// ========================================================================

// 解析操作类型字符串到枚举
OpCode parse_op_code(const char* op_str) {
    if (strcmp(op_str, "ALLOC") == 0) return OP_ALLOC;
    if (strcmp(op_str, "FREE") == 0) return OP_FREE;
    if (strcmp(op_str, "COPY_IN") == 0) return OP_COPY_IN;
    if (strcmp(op_str, "MOVE") == 0) return OP_MOVE;
    if (strcmp(op_str, "CONV") == 0) return OP_CONV;
    return OP_OTHER;
}

// 解析数据类型字符串到枚举
TypeCode parse_type_code(const char* type_str) {
    if (strcmp(type_str, "L1") == 0) return TYPE_L1;
    if (strcmp(type_str, "UB") == 0) return TYPE_UB;
    if (strcmp(type_str, "L0A") == 0) return TYPE_L0A;
    if (strcmp(type_str, "L0B") == 0) return TYPE_L0B;
    if (strcmp(type_str, "L0C") == 0) return TYPE_L0C;
    return TYPE_OTHER;
}

// 计算CSV文件行数
int count_csv_lines(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) return -1;
    
    int lines = 0;
    char buffer[1024];
    
    // 跳过标题行
    if (fgets(buffer, sizeof(buffer), file)) {
        lines = 0; // 重置，不计算标题行
    }
    
    while (fgets(buffer, sizeof(buffer), file)) {
        lines++;
    }
    
    fclose(file);
    return lines;
}

// 从CSV文件加载图数据
Graph* load_graph_from_csv(const char* nodes_file, const char* edges_file) {
    printf("正在加载图数据...\n");
    
    // 1. 计算节点和边的数量
    int num_nodes = count_csv_lines(nodes_file);
    int num_edges = count_csv_lines(edges_file);
    
    if (num_nodes <= 0 || num_edges <= 0) {
        printf("错误：无法读取CSV文件或文件为空\n");
        return NULL;
    }
    
    printf("  检测到 %d 个节点，%d 条边\n", num_nodes, num_edges);
    
    // 2. 创建图对象
    Graph* g = create_graph(num_nodes, num_edges);
    if (!g) {
        printf("错误：内存分配失败\n");
        return NULL;
    }
    
    // 3. 加载节点数据
    FILE* nodes_fp = fopen(nodes_file, "r");
    if (!nodes_fp) {
        printf("错误：无法打开节点文件 %s\n", nodes_file);
        free_graph(g);
        return NULL;
    }
    
    char line[1024];
    // 跳过标题行: Id,Op,BufId,Size,Type,Pipe,Cycles,Bufs
    fgets(line, sizeof(line), nodes_fp);
    
    for (int i = 0; i < num_nodes; i++) {
        if (!fgets(line, sizeof(line), nodes_fp)) {
            printf("错误：节点文件行数不匹配\n");
            fclose(nodes_fp);
            free_graph(g);
            return NULL;
        }
        
        // 解析CSV行: Id,Op,BufId,Size,Type,Pipe,Cycles,Bufs
        char* token;
        char* line_copy = strdup(line);
        char* original_line = strdup(line); // 保留原始行用于Bufs字段解析
        
        // Id
        token = strtok(line_copy, ",");
        g->nodes[i].id = atoi(token);
        
        // Op
        token = strtok(NULL, ",");
        g->nodes[i].op_code = parse_op_code(token);
        
        // BufId
        token = strtok(NULL, ",");
        g->nodes[i].buf_id = (token && strlen(token) > 0) ? atoi(token) : -1;
        
        // Size
        token = strtok(NULL, ",");
        g->nodes[i].size = (token && strlen(token) > 0) ? atoi(token) : 0;
        
        // Type
        token = strtok(NULL, ",");
        g->nodes[i].type_code = parse_type_code(token);
        
        // Pipe
        token = strtok(NULL, ",");
        if (token && strlen(token) > 0) {
            strncpy(g->nodes[i].pipe, token, sizeof(g->nodes[i].pipe) - 1);
            g->nodes[i].pipe[sizeof(g->nodes[i].pipe) - 1] = '\0';
        } else {
            g->nodes[i].pipe[0] = '\0';
        }
        
        // Cycles
        token = strtok(NULL, ",");
        g->nodes[i].cycles = (token && strlen(token) > 0) ? atoi(token) : 0;
        
        // Bufs字段解析（复杂逻辑，可能包含引号和逗号分隔列表）
        token = strtok(NULL, ",");
        g->nodes[i].bufs = NULL;
        g->nodes[i].bufs_count = 0;
        
        if (token && strlen(token) > 0) {
            // 处理可能的引号和剩余的行内容
            char bufs_content[256] = {0};
            
            // 如果token以引号开头，需要读取到下一个引号
            if (token[0] == '"') {
                // 移除开头的引号
                strcpy(bufs_content, token + 1);
                
                // 如果没有结束引号，继续读取
                if (bufs_content[strlen(bufs_content) - 1] != '"') {
                    char* next_token;
                    while ((next_token = strtok(NULL, ",")) != NULL) {
                        strcat(bufs_content, ",");
                        strcat(bufs_content, next_token);
                        if (next_token[strlen(next_token) - 1] == '"') {
                            break;
                        }
                    }
                }
                
                // 移除结束的引号
                int len = strlen(bufs_content);
                if (len > 0 && bufs_content[len - 1] == '"') {
                    bufs_content[len - 1] = '\0';
                }
            } else {
                strcpy(bufs_content, token);
            }
            
            // 解析逗号分隔的数字列表
            if (strlen(bufs_content) > 0) {
                // 首先计算数字的个数
                int count = 1;
                for (int j = 0; bufs_content[j]; j++) {
                    if (bufs_content[j] == ',') count++;
                }
                
                // 分配内存
                g->nodes[i].bufs = malloc(count * sizeof(int));
                g->nodes[i].bufs_count = 0;
                
                // 解析每个数字
                char* bufs_copy = strdup(bufs_content);
                char* num_token = strtok(bufs_copy, ",");
                while (num_token && g->nodes[i].bufs_count < count) {
                    // 去除空格
                    while (*num_token == ' ') num_token++;
                    char* end = num_token + strlen(num_token) - 1;
                    while (end > num_token && *end == ' ') end--;
                    *(end + 1) = '\0';
                    
                    if (strlen(num_token) > 0) {
                        g->nodes[i].bufs[g->nodes[i].bufs_count++] = atoi(num_token);
                    }
                    num_token = strtok(NULL, ",");
                }
                free(bufs_copy);
            }
        }
        
        free(line_copy);
        free(original_line);
    }
    
    fclose(nodes_fp);
    printf("  节点数据加载完成\n");
    
    // 4. 加载边数据
    FILE* edges_fp = fopen(edges_file, "r");
    if (!edges_fp) {
        printf("错误：无法打开边文件 %s\n", edges_file);
        free_graph(g);
        return NULL;
    }
    
    // 跳过标题行: StartNodeId,EndNodeId
    fgets(line, sizeof(line), edges_fp);
    
    for (int i = 0; i < num_edges; i++) {
        if (!fgets(line, sizeof(line), edges_fp)) {
            printf("错误：边文件行数不匹配\n");
            fclose(edges_fp);
            free_graph(g);
            return NULL;
        }
        
        // 解析CSV行: StartNodeId,EndNodeId
        char* token;
        char* line_copy = strdup(line);
        
        // StartNodeId
        token = strtok(line_copy, ",");
        int start_id = atoi(token);
        
        // EndNodeId  
        token = strtok(NULL, ",");
        int end_id = atoi(token);
        
        // MATLAB中ID从0开始，但图对象索引从0开始，所以这里不需要+1
        // 注意：需要根据ID找到实际的节点索引
        int start_idx = -1, end_idx = -1;
        
        // 线性搜索节点ID对应的索引 (可优化为哈希表)
        for (int j = 0; j < num_nodes; j++) {
            if (g->nodes[j].id == start_id) start_idx = j;
            if (g->nodes[j].id == end_id) end_idx = j;
        }
        
        if (start_idx >= 0 && end_idx >= 0) {
            add_edge(g, start_idx, end_idx);
        } else {
            printf("警告：找不到边 %d -> %d 对应的节点\n", start_id, end_id);
        }
        
        free(line_copy);
    }
    
    fclose(edges_fp);
    printf("  边数据加载完成\n");
    
    // 5. 计算传递闭包
    printf("  正在计算依赖关系（传递闭包）...\n");
    compute_transitive_closure(g);
    printf("  传递闭包计算完成\n");
    
    printf("图数据加载成功！\n");
    return g;
}
